package ${initProjectVo.packageNameValue}.core.log;

import ${initProjectVo.packageNameValue}.core.annotation.OperationLogs;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
* @author Faye.Wang
* @version 1.0
* @date 2020/9/6 10:35
* @Description 统一操作日志，记录所有请求请求参数
*/
@Aspect
@Component
public class LogAspect {

    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
    private final DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();

    private final SpelExpressionParser parser = new SpelExpressionParser();

    @Pointcut("@annotation(${initProjectVo.packageNameValue}.core.annotation.OperationLogs)")
        public void logPoint(){//这就是个标志，爱叫啥叫啥，给下面用的
    }


    @Around("logPoint()")
    public Object logPointCut(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Method method = getAnnotationMethod(proceedingJoinPoint);
        OperationLogs annotations = method.getAnnotation(OperationLogs.class);
        // 是否在方法之前前拦截
        if(annotations.executeBefore()){
            annotationExecute(annotations,proceedingJoinPoint,method);
        }

        return proceedingJoinPoint.proceed();
    }

    private void annotationExecute(OperationLogs operationLogs,JoinPoint joinPoint,Method method){
        String recordId = operationLogs.recordId();
        String operationName = operationLogs.operationName();
        String methodName = operationLogs.methodName();
        String methodType = operationLogs.methodType();;
        String logMsg = operationLogs.logMsg();

        StringBuffer stringBuffer = new StringBuffer("审计日志：用户[");

        Object[] arguments = joinPoint.getArgs();
        String[] params = discoverer.getParameterNames(method);
        StandardEvaluationContext context = LogRecordContext.getContext();
        LogInfo logInfo = new LogInfo();
        if (params != null) {
            for (int len = 0; len < params.length; len++) {
                context.setVariable(params[len], arguments[len]);
            }
        }

        if(StringUtils.isNoneBlank(operationName)){
            Expression expression = parser.parseExpression(operationName);
            String operationNameTemp = expression.getValue(context,String.class);
            logInfo.setOperationName(operationNameTemp);
            stringBuffer.append(operationNameTemp).append("]");
        }

        if(StringUtils.isNoneBlank(recordId)){
            Expression expression = parser.parseExpression(recordId);
            String recordIdTemp = expression.getValue(context,String.class);
            stringBuffer.append(" 业务数据ID：["+recordIdTemp).append("]");
            logInfo.setRecordId(recordIdTemp);
        }

        if(StringUtils.isNoneBlank(methodName)){
            Expression expression = parser.parseExpression(methodName);
            String methodNameTmp = expression.getValue(context,String.class);
            stringBuffer.append(" 业务名称：["+methodNameTmp).append("]");
            logInfo.setMethodName(methodNameTmp);
        }

        if(StringUtils.isNoneBlank(methodType)){
            Expression expression = parser.parseExpression(methodName);
            String methodNameTmp = expression.getValue(context,String.class);
            stringBuffer.append(" 业务操作：["+methodNameTmp).append("]");
            logInfo.setMethodName(methodNameTmp);
        }
        logMsg = stringBuffer.toString();

        logger.trace(logMsg);
    }




    private  Method getAnnotationMethod(JoinPoint joinPoint){
            Method method = null;
        try {
            Signature signature = joinPoint.getSignature();
            MethodSignature ms = (MethodSignature) signature;
            Object target = joinPoint.getTarget();
            method = target.getClass().getMethod(ms.getName(), ms.getParameterTypes());
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        return method;
    }
}
